/*
    backend for TimeTagger, an OpalKelly based single photon counting library
    Copyright (C) 2011  Markus Wick <wickmarkus@web.de>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <iostream>
#include <sstream>
#include <stdarg.h>

#include "Iterator.h"

#include "Logger.h"
DECLARE_LOG_SUPPORT(MODULES)

Iterator::Iterator(int chan) {
	debug("Iterator created.");

	registerChannel(chan);
	channel = chan;
	clear();
	start();
}

Iterator::~Iterator() {
	stop();
}

const char *Iterator::getClassName() {
	return "Iterator";
}

const char *Iterator::getScpiCommand()  {
	return ":CONFigure:ITERator";
}

std::string Iterator::getScpiParameters() {
	std::stringstream ss;
	ss << "(chan" << channel << ')';
	return ss.str();
}

void Iterator::getMeta(long long **ARGOUTVIEWM_ARRAY2, int *DIM1) {
	int sz=1;
	(*ARGOUTVIEWM_ARRAY2) = new long long [sz];
	(*ARGOUTVIEWM_ARRAY2)[0]=channel;

	(*DIM1)=sz;
}

Iterator* Iterator::__iter__() {
	return this;
}

long long Iterator::next() {
	while(1) {
		lock();
		bool empty = q.empty();
		long long wert = 0;
		if(!empty) {
			wert = q.front();
			q.pop();
		}
		unlock();

		if(!empty)
			return wert;

		current_sleep(10);
	}
}

int Iterator::size() {
	lock();
	int wert = q.size();
	unlock();
	return wert;
}

void Iterator::clear() {
	lock();
	q = std::queue<long long>();
	unlock();
}

void Iterator::next(Tag* list, int count, long long time) {
	for(int i=0; i<count; i++) {
		if(list[i].overflow) {
			// TODO: push StopIteration
		} else if(list[i].chan == channel)
			q.push(list[i].time);
	}
}



OverFlow::OverFlow() {
	debug("Overflow created.");
	clear();
	start();
}

OverFlow::~OverFlow() {
	stop();
}

const char *OverFlow::getClassName() {
	return "Overflow";
}

const char *OverFlow::getScpiCommand()  {
	return ":CONFigure:OVERflow";
}

std::string OverFlow::getScpiParameters() {
	return "";
}
void OverFlow::getMeta(long long **ARGOUTVIEWM_ARRAY2, int *DIM1) {
	int sz=1;
	(*ARGOUTVIEWM_ARRAY2) = new long long [sz];
	(*ARGOUTVIEWM_ARRAY2)[0]=overflows;

	*DIM1=sz;
}

void OverFlow::clear() {
	lock();
	overflows = 0;
	show_next = 0;
	std::cout << "clear overflows..." << std::endl;
	unlock();
}

void OverFlow::next(Tag* list, int count, long long time) {
	for(int i=0; i<count; i++) {
		if(list[i].overflow) {
			overflows++;
			if(show_next > list[i].time) {
				std::cout << "Overflows: " << overflows << std::endl;
				show_next = list[i].time+1000000000000L;
			}
		}
	}
	if(time > show_next) show_next = time;
}
	
Dump::Dump(std::string _filename) {
	debug("Dump created.");
	filename = _filename;
	output_file = 0;
	clear();
	start();
}

Dump::~Dump() {
	stop();
	output_file->close();
	delete output_file;
}

const char *Dump::getClassName() {
	return "Dump";
}

const char *Dump::getScpiCommand()  {
	return ":CONFigure:DUMP";
}

std::string Dump::getScpiParameters() {
	std::stringstream ss;
	ss << "\"" << filename << "\"";
	return ss.str();
}

void Dump::getMeta(long long **ARGOUTVIEWM_ARRAY2, int *DIM1) {
	ARGOUTVIEWM_ARRAY2=0;
	DIM1=0;
}

void Dump::clear() {
	lock();
	if(output_file) {
		output_file->close();
		delete output_file;
	}
	output_file = new std::ofstream(filename.c_str(), std::ios::out | std::ios::trunc | std::ios::binary);
	unlock();
}
void Dump::next(Tag* list, int count, long long time) {
	output_file->write( (char*)list, count * sizeof(Tag));
}

Chans::Chans() {
	debug("Chans created.");
	start();
}
Chans::~Chans() {
	stop();
}

const char *Chans::getClassName() {
	return "Chans";
}

const char *Chans::getScpiCommand()  {
	return ":CONFigure:CHANnel";
}

std::string Chans::getScpiParameters() {
	return "";
}
void Chans::getMeta(long long **ARGOUTVIEWM_ARRAY2, int *DIM1) {
	ARGOUTVIEWM_ARRAY2=0;
	DIM1=0;
}

void Chans::registerChannel(int chan) {
	_Iterator::registerChannel(chan);
}
void Chans::unregisterChannel(int chan) {
	_Iterator::unregisterChannel(chan);
}
void Chans::clear() {
	for(int i=0; i<channels; i++)
		_Iterator::unregisterChannel(i);
}

void Chans::next(Tag* list, int count, long long time) {

}


